/*
获取accesstoken
是公众号的 全局唯一 接口 调用凭据
特点：
需要512空间
有效期2小时
接口次数2000次
 */
//引入 request-promise-native
const rq=require('request-promise-native');
// 引入fs
const {writeFile,readFile}=require('fs');

const {appID,appsecret}=require('../config')


class Wechat {
    constructor(){

    }
    /*
      用来获取access_token
     */
    getAccessToken (){
        const url=`https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=${appID}&secret=${appsecret}`
        // console.log(url)
        //发送请求，服务器端么法使用ajax，我们使用一些库来实现
        /*
        request
        request-promise-native 这个库依赖于第一个库，所以都要下载.返回值是一个
        promise对象
         */
        return new Promise((resolve,reject)=>{
            rq({
                method:'GET',
                url,
                json:true
            }).then(res=>{
                // console.log(res)
                res.expires_in=Date.now()+(res.expires_in-300)*1000;
                //将promise的对象状态改为成功的状态
                resolve(res)
            }).catch(res=>{
                // console.log(res)
                //将promise的对象状态改为失败的状态
                reject('getAccessToken出了问题'+res)
            })
        })
    }

    /*
    save用来保存 access_token 的方法
    @param accessToken 用来保存的凭据
     */
    saveAccessToken(accessToken){
        /*
        *  文件  数据
        *
        *  accessToken 不能直接写，要不不会变成【object】
        *  writeFile是异步方法
        * */
        return  new Promise((resolve,reject)=>{
            accessToken=JSON.stringify(accessToken);
            writeFile('./accessToken.txt', accessToken, err=>{
                if(!err){
                    console.log('文件保存成功');
                    resolve(accessToken);
                }else{
                    reject('saveAccessToken方法除了问题：'+err);
                }
            })
        })
    }

    /*
    read用来读取 access_token 的方法
     */
    readAccessToken(){
        /*
        *  文件  数据
        *  readFile是异步方法
        * */
        return  new Promise((resolve,reject)=>{
            readFile('./accessToken.txt', (err,data)=>{
                if(!err){
                    console.log('文件读取成功');
                    //将json字符串 转成  js对象
                    data=JSON.parse(data);
                    resolve(data);
                }else{
                    console.log('文件读取失败');
                    reject('readAccessToken方法除了问题：'+err);
                }
            })
        })
    }

    /*
     accessToken 是否有效
     @param data
     */
    isValidAccessToken (data){
        // 检测传入的参数是否有效
        //  是否有数据   数据是否有token    数据是否有时间
        if(!data && !data.access_token && !data.expires_in){
            return false;
        }

         //检测access_token 是否在有效期内
         if(data.expires_in< Date.now()){
             // 过期了
             return false;
         }else{
             //没有过期
             return true;
         }
    }


    /*
    fetchAccessToken
    用来获取没有过期的access_token
    @return {Promise<any>} access_token
     */
    fetchAccessToken (){
        //先判断 对象上 是否有token 和过期时间 和 这个token是否有效
        if(this.access_token && this.expires_in && this.isValidAccessToken(this)){
        // 如果有效 就返回一个 promise的成功状态 自己定义一个对象，不直接返回this，因为this上东西太多
            return Promise.resolve({
                access_token:this.access_token,
                expires_in:this.expires_in
            })
        }
        // 这是 fetchAccessToken最终的返回值
       return this.readAccessToken()
                .then(async res=>{
                    //本地有文件
                    //判断文件是否过期
                    if(this.isValidAccessToken(res)){
                        //没过期
                       return Promise.resolve(res)
                    }else{
                        //过期了
                        // 发送请求获取access_token
                        let res=await this.getAccessToken()
                        //保存下来 本地文件
                        await this.saveAccessToken(res)
                        //将请求回来的access_token 返回出去
                        return Promise.resolve(res)
                    }
                })
                .catch(async err=>{
                    //本地没有文件
                    //过期了
                    // 发送请求获取access_token
                    let res=await this.getAccessToken()
                    //保存下来 本地文件
                    await this.saveAccessToken(res)
                    //将请求回来的access_token 返回出去
                    return Promise.resolve(res)
                })
                .then(res=>{
                    //将access_token挂载到this上
                    this.access_token=res.access_token;
                    this.expires_in=res.expires_in;
                    //返回res包装了一层promise对象（此对象是成功的状态）
                    //是this.readAccessToken()最终的返回值
                    return Promise.resolve(res)
                })
    }

}


/*
* 测试我们上面的方法
* */
/*let w=new Wechat();

new Promise((resolve,reject)=>{
    w.readAccessToken()
    .then(res=>{
        //本地有文件
         //判断文件是否过期
        if(w.isValidAccessToken(res)){
            resolve(res)
        }else{
            w.getAccessToken()
                .then(res=>{
                    //保存下来 本地文件
                    w.saveAccessToken(res)
                        .then(res=>{
                            resolve(res)
                        })
                })
        }
    })
    .catch(res=>{
        //本地没有文件
        //发送请求获取 access_token
        w.getAccessToken()
            .then(res=>{
                //保存下来 本地文件
                w.saveAccessToken(res)
                    .then(res=>{
                        resolve(res)
                    })
            })
    })
}).then(res=>{
    //这里最终拿到了 没有问题的 res
    console.log('最终结果');
    console.log(res)
})*/
